﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using GalaSoft.MvvmLight.Command;
using GalaSoft.MvvmLight.Messaging;
using Reactor.Client.Messages;
using Reactor.Client.Services;
using Reactor.Client.Web.Data;

namespace Reactor.Client.ViewModel
{
    public class CoreViewModel : ServiceBaseViewModel
    {
        #region Fields

        private readonly IMessenger _messenger;
        private readonly IReactorServiceAgent _reactorServiceAgent;
        private readonly IDialogService _dialogService;
        private ReactorCore _core;
        private ServiceViewModel _selectedService;
        private string _serviceCount;
        private Color _serviceCountLabelColor;

        #endregion

        public CoreViewModel(IMessenger messenger, IReactorServiceAgent reactorServiceAgent, IDialogService dialogService, ReactorCore core) : base(reactorServiceAgent)
        {
            if (messenger == null) throw new ArgumentNullException("messenger");
            if (reactorServiceAgent == null) throw new ArgumentNullException("reactorServiceAgent");
            if (dialogService == null) throw new ArgumentNullException("dialogService");
            if (core == null) throw new ArgumentNullException("core");

            _messenger = messenger;
            _reactorServiceAgent = reactorServiceAgent;
            _dialogService = dialogService;
            _core = core;

            _messenger.Register<ServiceSelectedEvent>(this, HandleServiceSelectedEvent);

            LoadCoreEntity(core);

            DetermineOnlineStatus();

            Services = new ObservableCollection<ServiceViewModel>();
            _reactorServiceAgent.GetAllServicesByCore(Name, LoadServices);
        }

        public string ServiceCount
        {
            get { return _serviceCount; }
            set
            {
                if (value == _serviceCount) return;

                _serviceCount = value;
                RaisePropertyChanged("ServiceCount");
            }
        }

        public ICommand OpenServicesDialogCommand
        {
            get { return new RelayCommand(SendOpenServicesRequest); }
        }

        public ICommand OpenAdoptionDialogCommand
        {
            get { return new RelayCommand(OpenAdoptionDialog); }
        }

        public Color ServiceCountLabelColor
        {
            get { return _serviceCountLabelColor; }
            set
            {
                if (value == _serviceCountLabelColor) return;

                _serviceCountLabelColor = value;
                RaisePropertyChanged("ServiceCountLabelColor");
            }
        }

        public ServiceViewModel SelectedService
        {
            get { return _selectedService; }
            set
            {
                if (value == _selectedService) return;

                _selectedService = value;
                RaisePropertyChanged("SelectedService");
            }
        }

        public ObservableCollection<ServiceViewModel> Services { get; private set; }

        public void LoadCoreEntity(ReactorCore core)
        {
            _core = core;

            Name = core.Name;
            ServiceCount = core.ServiceCount.ToString();
        }

        private void SendOpenServicesRequest()
        {
            SendCoreSelectedEvent();
            Messenger.Default.Send(new NavigateToServicesRequest());
        }

        private void SendCoreSelectedEvent()
        {
            Messenger.Default.Send(new CoreSelectedEvent { CoreViewModel = this });
        }

        private void OpenAdoptionDialog()
        {
            SendCoreSelectedEvent();
            _dialogService.ShowAdoptServiceDialog();
        }

        protected override void DetermineOnlineStatus()
        {
            if(!_core.LastSeen.HasValue || _core.LastSeen.Value == DateTime.MinValue)
            {
                IsOnline = false;
                return;
            }

            var interval = TimeSpan.FromMinutes(1);
            if (HealthCheckInterval.HasValue)
                interval = HealthCheckInterval.Value;

            var pastInterval = (DateTime.Now - _core.LastSeen) > interval;
            IsOnline = !pastInterval;
        }

        protected override void UpdateStatusImage()
        {
            if(_core == null || Services == null) return; // This can happen if the base has called this method before this derived class's constructor is executed.

            if (Services.Count == 0)
            {
                base.UpdateStatusImage();
                ServiceCountLabelColor = Colors.White;
                return;
            }

            if (Services.Count(s => s.IsOnline) >= _core.ServiceCount)
            {
                base.UpdateStatusImage();
                ServiceCountLabelColor = Colors.White;
            }
            else
            {
                StatusImage = new BitmapImage(new Uri(Application.Current.Host.Source, "../Images/StatusLight-Orange.png"));
                ServiceCountLabelColor = Colors.Red;
            }
        }

        private void LoadServices(IEnumerable<ServiceViewModel> obj)
        {
            foreach (var serviceViewModel in obj)
                Services.Add(serviceViewModel);

            UpdateStatusImage();
        }

        private void HandleServiceSelectedEvent(ServiceSelectedEvent evnt)
        {
            SelectedService = evnt.SelectedService;
        }
    }
}
